﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;

namespace _1945
{
    /// <summary>
    /// Returns a sprite from the spritesheet
    /// </summary>
    public class SpriteFactory
    {

        /// <summary>
        /// Singleton pattern. This implementation is not thread safe
        /// </summary>
        private static SpriteFactory instance;
        public static SpriteFactory Instance
        {
            get
            {
                if (instance == null)
                {
                    instance = new SpriteFactory();
                }
                return instance;
            }
        }

        #region Sprites
        /// <summary>
        /// Player sprites
        /// </summary>
        Sprite bigPlayerShipWithShadow, bigPlayerShipNoShadow;

        /// <summary>
        /// Bullet sprites
        /// </summary>
        Sprite smallBullet, bigBullet, up, upleft, upright, left, right, downleft, downright, updouble, downdouble;

        /// <summary>
        /// Explosion sprites
        /// </summary>
        Sprite smallExplosion, bigExplosion;

        /// <summary>
        /// Islands
        /// </summary>
        Sprite vegetatedIsland, rockyIsland, browRockIsland;

        /// <summary>
        /// Powerups
        /// </summary>
        Sprite  fire_D_L_R_Ul_Ur, fire_L_R_D, fire_L_R, fire_double_U, ship_with_shield, airforce_pin, ship_with_arrow, ship,
                power_up_yellow, power_up_orange, bomb, mine;

        /// <summary>
        /// Enemies
        /// </summary>
        Sprite DF_A_small_Gray, DF_A_small_White, DF_A_small_Green, DF_A_small_Blue, DF_A_small_Orange, UF_A_big_Military_Camouflage;

        Sprite blackSprite;
        TimeSpan zero = TimeSpan.Zero;
        int defaultSpriteFPS = 30;
        #endregion

        #region enums
        public enum player
        {
            bigShipWithShadow = 1,
            bigShipNoShadow   = 2
        }

        public enum bullets
        {
            smallBullet = 1,
            bigBullet   = 2,
            up          = 3,
            upleft      = 4,
            upright     = 5,
            left        = 6,
            right       = 7,
            downleft    = 8,
            downright   = 9,
            updouble    = 10,
            downdouble  = 11
        }

        public enum explosions
        {
            small,
            big
        }

        public enum islands
        {
            vegetatedIsland  = 1,
            rockyIsland      = 2,
            brownRock        = 3
       }

        /// <summary>
        /// First letter denotes what type of upgrade, letters after that determine characteristics.
        /// </summary>
        public enum powerups
        {
            fire_D_L_R_Ul_Ur = 1,   //Fire bullets Down, Left, Right, UpLeft & UpRight
            fire_L_R_D       = 2,   //Fire bullets Left, Right, Down
            fire_L_R         = 3,   //Fire bullets Left, Right
            fire_double_U    = 4,   //Fire two bullets Up
            ship_with_shield = 5,   //Change description later - INVINCIBILITY ???
            airforce_pin     = 6,   //Change description later
            ship_with_arrow  = 7,   //Change description later - SPEED UP ???
            ship             = 8,   //Change description later - EXTRA LIFE ???
            power_up_yellow  = 9,   //
            power_up_orange  = 10,  //
            bomb             = 11,  //
            mine             = 12   //
        }
        
        /// <summary>
        /// First letter(s) denot which way enemy is facing - DF means Down Facing. 
        /// A means animated. If there's no A, enemy consists of a single sprite
        /// </summary>
        public enum enemies
        {
            UF_A_big_Military_Camouflage,
            DF_A_small_Gray     = 1,
            DF_A_small_White    = 2,
            DF_A_small_Green    = 3,
            DF_A_small_Blue     = 4,
            DF_A_small_Orange   = 5
        }
        #endregion

        #region Constructor

        private SpriteFactory()
        {
            //Player
            bigPlayerShipNoShadow = new Sprite(getPlayerRectangle(player.bigShipNoShadow), defaultSpriteFPS, zero, zero, 1, 3);
            bigPlayerShipWithShadow = new Sprite(getPlayerRectangle(player.bigShipWithShadow), defaultSpriteFPS, zero, zero, 3, 1);
            
            //Bullets
            smallBullet = new Sprite(getBulletRectangle(bullets.smallBullet));
            bigBullet = new Sprite(getBulletRectangle(bullets.bigBullet));
            up = new Sprite(getBulletRectangle(bullets.up));
            upleft = new Sprite(getBulletRectangle(bullets.upleft));
            upright = new Sprite(getBulletRectangle(bullets.upright));
            left = new Sprite(getBulletRectangle(bullets.left));
            right = new Sprite(getBulletRectangle(bullets.right));
            downleft = new Sprite(getBulletRectangle(bullets.downleft));
            downright = new Sprite(getBulletRectangle(bullets.downright));
            updouble = new Sprite(getBulletRectangle(bullets.updouble));
            downdouble = new Sprite(getBulletRectangle(bullets.downdouble));

            //Explosions
            smallExplosion = new Sprite(getExplosionRectangle(explosions.small), defaultSpriteFPS, new TimeSpan(0, 0, 0, 0, 600), zero, 1, 6);
            bigExplosion = new Sprite(getExplosionRectangle(explosions.big), defaultSpriteFPS, new TimeSpan(0, 0, 0, 0, 467), zero, 1, 6);

            //Island
            vegetatedIsland = new Sprite(getIslandRectangle(islands.vegetatedIsland));
            rockyIsland = new Sprite(getIslandRectangle(islands.rockyIsland));
            browRockIsland = new Sprite(getIslandRectangle(islands.brownRock));

            //Powerups
            fire_D_L_R_Ul_Ur = new Sprite(getPowerUpRectangle(powerups.fire_D_L_R_Ul_Ur));
            fire_L_R_D = new Sprite(getPowerUpRectangle(powerups.fire_L_R_D));
            fire_L_R = new Sprite(getPowerUpRectangle(powerups.fire_L_R));
            fire_double_U = new Sprite(getPowerUpRectangle(powerups.fire_double_U));
            ship_with_shield = new Sprite(getPowerUpRectangle(powerups.ship_with_shield));
            airforce_pin = new Sprite(getPowerUpRectangle(powerups.airforce_pin));
            ship_with_arrow = new Sprite(getPowerUpRectangle(powerups.ship_with_arrow));
            ship = new Sprite(getPowerUpRectangle(powerups.ship));
            power_up_yellow = new Sprite(getPowerUpRectangle(powerups.power_up_yellow));
            power_up_orange = new Sprite(getPowerUpRectangle(powerups.power_up_orange));
            bomb = new Sprite(getPowerUpRectangle(powerups.bomb));
            mine = new Sprite(getPowerUpRectangle(powerups.mine));

            //enemies
            DF_A_small_Gray = new Sprite(getEnemyRectangle(enemies.DF_A_small_Gray), defaultSpriteFPS, zero, zero, 1, 3);
            DF_A_small_White = new Sprite(getEnemyRectangle(enemies.DF_A_small_White), defaultSpriteFPS, zero, zero, 1, 3);
            DF_A_small_Green = new Sprite(getEnemyRectangle(enemies.DF_A_small_Green), defaultSpriteFPS, zero, zero, 1, 3);
            DF_A_small_Blue = new Sprite(getEnemyRectangle(enemies.DF_A_small_Blue), defaultSpriteFPS, zero, zero, 1, 3);
            DF_A_small_Orange = new Sprite(getEnemyRectangle(enemies.DF_A_small_Orange), defaultSpriteFPS, zero, zero, 1, 3);
            UF_A_big_Military_Camouflage = new Sprite(getEnemyRectangle(enemies.UF_A_big_Military_Camouflage), defaultSpriteFPS, zero, zero, 1, 3);

            //default sprite
            blackSprite = new Sprite(new Rectangle(433, 362, 34, 34));
        }

        #endregion

        #region Sprite returners
        public Sprite getPlayerSprite(player whichplayer)
        {
            switch (whichplayer)
	        {
		        case player.bigShipWithShadow:
                     return bigPlayerShipWithShadow;
                case player.bigShipNoShadow:
                     return bigPlayerShipNoShadow;
	        }
            return blackSprite;
        }

        public Sprite getBulletSprite(bullets whichBullet)
        {
            switch (whichBullet)
            {
                case bullets.smallBullet:
                    return smallBullet;
                case bullets.bigBullet:
                    return bigBullet;
                case bullets.up:
                    return up;
                case bullets.upleft:
                    return upleft;
                case bullets.upright:
                    return upright;
                case bullets.left:
                    return left;
                case bullets.right:
                    return right;
                case bullets.downleft:
                    return downleft;
                case bullets.downright:
                    return downright;
                case bullets.updouble:
                    return updouble;
                case bullets.downdouble:
                    return downdouble;
            }
            return blackSprite;
        }

        public Sprite getIslandSprite(islands whichIsland)
        {
            switch (whichIsland)
            {
                case islands.vegetatedIsland:
                    return vegetatedIsland;
                case islands.rockyIsland:
                    return rockyIsland;
                case islands.brownRock:
                    return browRockIsland;
            }
            return blackSprite;
        }

        public Sprite getExplosionSprite(explosions whichExplosion, TimeSpan totalElapsed)
        {
            switch (whichExplosion)
            {
                case explosions.small:
                    smallExplosion.setAnimationStartedTime(totalElapsed);
                    return smallExplosion;
                case explosions.big:
                    bigExplosion.setAnimationStartedTime(totalElapsed);
                    return bigExplosion;
            }
            return blackSprite;
        }

        public Sprite getPowerupSprite(powerups whichPowerup)
        {
            switch (whichPowerup)
            {
                case powerups.fire_D_L_R_Ul_Ur:
                    return fire_D_L_R_Ul_Ur;
                case powerups.fire_L_R_D:
                    return fire_L_R_D;
                case powerups.fire_L_R:
                    return fire_L_R;
                case powerups.fire_double_U:
                    return fire_double_U;
                case powerups.ship_with_shield:
                    return ship_with_shield;
                case powerups.airforce_pin:
                    return airforce_pin;
                case powerups.ship_with_arrow:
                    return ship_with_arrow;
                case powerups.ship:
                    return ship;
                case powerups.power_up_yellow:
                    return power_up_yellow;
                case powerups.power_up_orange:
                    return power_up_orange;
                case powerups.bomb:
                    return bomb;
                case powerups.mine:
                    return mine;
            }
            return blackSprite;
        }

        public Sprite getEnemySprite(enemies whichEnemy)
        {
            switch (whichEnemy)
            {
                case enemies.DF_A_small_Gray:
                    return DF_A_small_Gray;
                case enemies.DF_A_small_White:
                    return DF_A_small_White;
                case enemies.DF_A_small_Green:
                    return DF_A_small_Green;
                case enemies.DF_A_small_Blue:
                    return DF_A_small_Blue;
                case enemies.DF_A_small_Orange:
                    return DF_A_small_Orange;
                case enemies.UF_A_big_Military_Camouflage:
                    return UF_A_big_Military_Camouflage;
            }
            return blackSprite;
        }
        
        #endregion

        private Rectangle getPlayerRectangle(player whichPlayer)
        {
            switch (whichPlayer)
            {
                case player.bigShipWithShadow:
                    return new Rectangle(300, 102, 66, 199);

                case player.bigShipNoShadow:
                    return new Rectangle(3, 399, 199, 66);
            }

            return new Rectangle();
        }

        private Rectangle getBulletRectangle(bullets whichBullet)
        {
            switch (whichBullet)
            {
                case bullets.smallBullet:
                    return new Rectangle(84, 215, 5, 5);

                case bullets.bigBullet:
                    return new Rectangle(49, 214, 8, 8);

                case bullets.up:
                    return new Rectangle(48, 176, 8, 18);

                case bullets.upleft:
                    return new Rectangle(13, 245, 12, 12);

                case bullets.upright:
                    return new Rectangle(47, 245, 12, 12);

                case bullets.left:
                    return new Rectangle(145, 248, 14, 6);

                case bullets.right:
                    return new Rectangle(177, 248, 14, 6);

                case bullets.downleft:
                    return new Rectangle(79, 244, 12, 12);

                case bullets.downright:
                    return new Rectangle(113, 244, 12, 12);

                case bullets.updouble:
                    return new Rectangle(11, 177, 16, 14);

                case bullets.downdouble:
                    return new Rectangle(11, 211, 16, 14);
            }
            return new Rectangle();
        }

        private Rectangle getIslandRectangle(islands whichIsland)
        {
            switch (whichIsland)
            {
                case islands.vegetatedIsland:
                    return new Rectangle(103, 499, 64, 64);

                case islands.rockyIsland:
                    return new Rectangle(168, 499, 64, 64);

                case islands.brownRock:
                    return new Rectangle(233, 499, 64, 64);
            }
            return new Rectangle();
        }

        private Rectangle getExplosionRectangle(explosions whichExplosion)
        {
            switch (whichExplosion)
            {
                case explosions.small:
                    return new Rectangle(69, 168, 199, 34);

                case explosions.big:
                    return new Rectangle(3, 300, 463, 66);
            }
            return new Rectangle();
        }

        private Rectangle getPowerUpRectangle(powerups whichPowerUp)
        {
            switch (whichPowerUp)
            {
                case powerups.fire_D_L_R_Ul_Ur:
                    return new Rectangle(3, 267, 34, 34);

                case powerups.fire_L_R_D:
                    return new Rectangle(36, 267, 34, 34);

                case powerups.fire_L_R:
                    return new Rectangle(69, 267, 34, 34);

                case powerups.fire_double_U:
                    return new Rectangle(102, 267, 34, 34);

                case powerups.ship_with_shield:
                    return new Rectangle(135, 267, 34, 34);

                case powerups.airforce_pin:
                    return new Rectangle(168, 267, 34, 34);

                case powerups.ship_with_arrow:
                    return new Rectangle(201, 234, 34, 34);

                case powerups.ship:
                    return new Rectangle(201, 267, 34, 34);

                case powerups.power_up_yellow:
                    return new Rectangle(234, 234, 34, 34);

                case powerups.power_up_orange:
                    return new Rectangle(234, 267, 34, 34);

                case powerups.bomb:
                    return new Rectangle(267, 267, 34, 34);

                case powerups.mine:
                    return new Rectangle(102, 201, 34, 34);
            }

            return new Rectangle();
        }
            
        private Rectangle getEnemyRectangle(enemies whichEnemy)
        {
            switch (whichEnemy)
            {
                case enemies.DF_A_small_Gray:
                    return new Rectangle(3, 465, 100, 34);

                case enemies.DF_A_small_White:
                    return new Rectangle(102, 465, 100, 34);

                case enemies.DF_A_small_Green:
                    return new Rectangle(201, 465, 100, 34);

                case enemies.DF_A_small_Blue:
                    return new Rectangle(300, 465, 100, 34);

                case enemies.DF_A_small_Orange:
                    return new Rectangle(3, 498, 100, 34);
                case enemies.UF_A_big_Military_Camouflage:
                    return new Rectangle(597, 13, 298, 75);
            }
            return new Rectangle();
        }

        public static Rectangle getBigGamePoster()
        {
            return new Rectangle(105, 576, 274, 140);
        }
    }
}
